import RNFS from "react-native-fs";
import { captureScreen } from "react-native-view-shot";
import dayjs from "dayjs";
import isSameOrBefore from "dayjs/plugin/isSameOrBefore";

// https://github.com/RonRadtke/react-native-blob-util#readme
import RNFetchBlob, { FetchBlobResponse, StatefulPromise } from "react-native-blob-util";

import getDeviceInfo from "@/utils/getDeviceInfo";
import { sliceFileSqlh, SliceFileSqliteType } from "@/sqlite/exports";
import config from "@/config";
import { Module } from "@/utils/nativeModules";

import type {
  DownFileOption,
  SliceDownloadOptionType,
  UploadFileOption,
  DownFileCallbackParams,
  BuildSliceToFileOption
} from "./type";
import type { CaptureOptions } from "react-native-view-shot";
import type { ResultSet } from "react-native-sqlite-storage";
import { PermissionsAndroid } from "react-native";

dayjs.extend(isSameOrBefore);

/**
 * 文件操作类, 包括:
 *  日志记录
 *  截图
 *  文件上传
 *  文件下载
 */
export default class FileOperate {
  /** 应用的 files 目录, 位置: /data/data/{包名}/files */
  public static filesDir = RNFS.DocumentDirectoryPath;

  /** 应用的主目录, 位置: /data/data/{包名} */
  public static mainDir = RNFetchBlob.fs.dirs.MainBundleDir;

  /** 应用的 cache 目录, 位置: /data/data/{包名}/cache */
  public static cacheDir = RNFS.CachesDirectoryPath;

  /** 系统下载目录 */
  public static downDir = RNFS.DownloadDirectoryPath;

  /** 进度间隔 */
  public static progressInterval = 3000;

  /** 删除多少天之前的日志文件 */
  public static deleteBeforeDay = 30;

  /** 获取外部文件读写权限 */
  getExternalFilePermission: boolean;
  /** 日志目录 */
  logDir: string;
  /** 素材目录 */
  resourceDir: string;
  /** 切片文件目录 */
  sliceFileDir: string;
  /** apk文件目录 */
  apksDir: string;
  /** 截图目录 */
  screenshotDir: string;
  /** 旧版本APP数据保存到新版本APP的文件路径 */
  oldAppstorageInfoFilePath: string;

  public constructor(public baseDir: string) {
    // 不需要申请权限, 但是点击文件无法看到日志, 素材等文件数据
    // this.baseDir = `${FileOperate.filesDir}/${baseDir}`;
    // this.getExternalFilePermission = false;

    // 需要外部文件读写权限, 会有个弹框, 需要点一下, 影响旧版app自动迁移, 但是可以从文件里看到日志, 素材等文件数据
    this.baseDir = `${FileOperate.downDir}/${baseDir}`;
    this.getExternalFilePermission = true;

    this.logDir = `${this.baseDir}/log`;
    this.resourceDir = `${this.baseDir}/resource`;
    this.sliceFileDir = `${this.baseDir}/sliceFile`;
    this.apksDir = `${this.baseDir}/apks`;
    this.screenshotDir = `${this.baseDir}/screenshot`;
    this.oldAppstorageInfoFilePath = `${this.baseDir}/${config.oldAppInfo.storageInfoFileName}`;
  }

  /** 错误处理 */
  static handleError(err: string) {
    if (config.IS_DEBUG) {
      console.log(err);
      getDeviceInfo()
        .then(res => {
          console.log("当前设备的详细信息: ", res);
        })
        .catch(err => {
          console.log("err: ", err);
        });
    }
  }

  /** 初始化 */
  public init(): Promise<string | void> {
    return new Promise(async (resolve, reject) => {
      try {
        // 先创建父级目录
        await this.mkdirDir(this.baseDir);

        const dirs = [this.logDir, this.resourceDir, this.sliceFileDir, this.apksDir, this.screenshotDir];
        for (let i = 0; i < dirs.length; i++) {
          const dir = dirs[i];
          const isExists = await RNFS.exists(dir);
          if (!isExists) {
            console.log("创建目录: ", dir);
            await this.mkdirDir(dir);
          }
        }

        resolve();
      } catch (err) {
        console.log("err: ", err);
        reject(err);
      }
    });
  }

  /** 创建目录 */
  public mkdirDir(dir: string): Promise<string> {
    return new Promise(async (resolve, reject) => {
      try {
        const isExists = await RNFS.exists(dir);
        if (!isExists) {
          if (config.IS_DEBUG) console.log(`创建目录 ${dir}`);
          await RNFS.mkdir(dir);
        }
        resolve(dir);
      } catch (err) {
        reject(err);
      }
    });
  }

  /** 时分秒 */
  public get getDayText() {
    return dayjs().format("YYYY-MM-DD HH:mm:ss");
  }

  /** 获取当天的日志文件地址 */
  public getTodayFile() {
    return this.logDir + dayjs().format("/YYYY_MM_DD.log");
  }

  /** 追加文本到日志文件 */
  public appendLogFile(level: "INFO" | "WARN" | "ERROR", ...args: any[]) {
    return new Promise<void>(async (resolve, reject) => {
      if (config.IS_DEBUG) {
        console.log(dayjs().format("HH:mm:ss"), level, ...args);
      }

      const text = JSON.stringify(args).slice(1, -1);

      // 写入内容
      const writeContent = `[${this.getDayText}] [${level}]: ${text}\n\n`;
      // 文件地址
      const filePath = this.getTodayFile();

      try {
        // 追加写入
        await RNFS.appendFile(filePath, writeContent);
        resolve();
      } catch (err) {
        reject(err);
      }
    });
  }

  /** 判断文件是否存在 */
  public exists(url: string) {
    return RNFS.exists(url);
  }

  /** 获取文件信息 */
  public stat(url: string) {
    return RNFS.stat(url);
  }

  /** 读取文件内容 */
  public readFile(url: string) {
    return RNFS.readFile(url, "utf8");
  }

  /** 写入文件内容 */
  public writeFile(url: string, content: string, encoding?: any) {
    return RNFS.writeFile(url, content, encoding);
  }

  /** 删除文件 */
  public rm(url: string) {
    return new Promise<void>(async resolve => {
      // 如果已经存在则会出现数据错乱的问题
      const isExists = await RNFS.exists(url).catch(err => {
        console.log("err: ", err);
      });
      // 如果已经存在则删除
      if (isExists) {
        await RNFS.unlink(url);
      } else {
        this.warn("删除的文件不存在: ", url);
      }
      resolve();
    });
  }

  /** 读取指定目录下面的所有文件 */
  public readDir(dir: string) {
    return RNFS.readDir(dir);
  }

  /** 读取当天的日志内容 */
  public readTodayFile() {
    return RNFS.readFile(this.getTodayFile(), "utf8");
  }

  /** 读取日志目录 */
  public readLogDir() {
    return this.readDir(this.logDir);
  }

  /** 清空当天的日志内容 */
  public clearTodayFile() {
    return RNFS.writeFile(this.getTodayFile(), "");
  }

  /** 删除多少天之前的日志文件 */
  public clearBeforeDayFile(beforeDay = FileOperate.deleteBeforeDay): Promise<void> {
    return new Promise(async (resolve, reject) => {
      try {
        const re = /\.log$/;
        // 上个月时间
        const nextMonth = dayjs().subtract(beforeDay, "day");
        this.info(`删除${beforeDay}天之前的日志, 上个月的日期是: ${nextMonth.format("YYYY-MM-DD")}`);

        const deleteFiles = [];
        const logFiles = await this.readLogDir();
        for (const log of logFiles) {
          const logDay = log.path.replace(re, "").split("/").pop();
          if (logDay) {
            // 是否在上个月之前
            const isFlog = dayjs(logDay.replace(/_/g, "-")).isSameOrBefore(nextMonth, "day");
            if (isFlog) {
              this.info(`删除日志文件 -> ${log.path}`);
              deleteFiles.push(this.rm(log.path));
            }
          }
        }
        await Promise.all(deleteFiles);
        resolve();
      } catch (err) {
        console.log("err: ", err);
        reject(err);
      }
    });
  }

  /** 上传文件 */
  public async uploadFile(opt: UploadFileOption) {
    return new Promise<FetchBlobResponse>(async (resolve, reject) => {
      try {
        this.info("开始上传文件: ", opt);
        const res = await RNFS.exists(opt.filePath);
        if (res) {
          // https://github.com/wkh237/react-native-fetch-blob?tab=readme-ov-file#multipartform-data-example-post-form-data-with-file-and-data
          const uploadRes = await RNFetchBlob.fetch(
            opt.method,
            opt.url,
            {
              "Content-Type": "multipart/form-data",
              ...(opt.headers || {})
            },
            [
              {
                name: opt.formDataKey, // 对应 formData 里的键
                filename: opt.fileName, // 上传给后台的文件名
                type: opt.mime,
                data: RNFetchBlob.wrap(opt.filePath)
              },
              ...(opt.otherFormData || [])
            ]
            // 上传进度, 每 1000ms 触发一次
          ).uploadProgress({ interval: FileOperate.progressInterval }, (written, total) => {
            const progress = (written / total) * 100;
            this.info(`${opt.filePath} 文件上传中: ${progress.toFixed(2)}%`);
          });

          if (uploadRes.data && uploadRes.data.indexOf(`"code":200`) === -1) {
            reject(new Error("文件上传失败: " + uploadRes.data));
            return;
          }

          this.info(`${opt.filePath} 文件上传成功: ${uploadRes.data}`);
          resolve(uploadRes);
        } else {
          reject(new Error("文件不存在"));
        }
      } catch (err) {
        reject(err);
      }
    });
  }

  /** 普通下载文件 */
  public downFile(opt: DownFileOption, getTask?: (task: StatefulPromise<FetchBlobResponse>) => void) {
    return new Promise<string | Error>(async resolve => {
      try {
        this.info("开始下载文件(不分片): ", opt);
        const task = RNFetchBlob.config({
          path: opt.downFileToNativePath,
          fileCache: true

          // 使用 DownloadManager 下载器管理会显示下载通知(需要外部文件读写权限)
          // addAndroidDownloads: {
          //   useDownloadManager: true,
          //   mediaScannable: true,
          //   notification: true,
          //   title: opt.title || "文件下载",
          //   description: opt.description || "文件正在下载中",
          //   mime: opt.mime,
          //   path: opt.downFileToNativePath
          // }
        })
          .fetch(opt.method, opt.url, opt.headers)
          // 下载进度
          .progress({ interval: FileOperate.progressInterval }, (received, total) => {
            if (Number(received) === 0 && Number(total) === -1) {
              this.info(`无法计算下载进度: received: ${received}, total: ${total} -> ${opt.url}`);
            } else {
              const progress = (Number(received) / Number(total)) * 100;
              this.info(`下载进度: ${progress.toFixed(2)}% -> ${opt.url}`);
            }
          });

        getTask && getTask(task);

        task.then(res => {
          this.info("文件下载成功, 位置: ", res.path());
          resolve(res.path());
        });
      } catch (err) {
        console.log("err: ", err);
        if (err instanceof Error) {
          resolve(err);
        } else {
          resolve(new Error("发生了异常"));
        }
      }
    });
  }

  /** 读取分片下载失败的文件的信息 */
  private readDownloadFileInfo(): Promise<SliceFileSqliteType[]> {
    return new Promise(async (resolve, reject) => {
      if (sliceFileSqlh) {
        const res = await sliceFileSqlh.getList<SliceFileSqliteType[]>();
        res.forEach(e => {
          // 解析请求头
          e.headers = JSON.parse(e.headers);
        });
        resolve(res);
      } else {
        console.log("数据初始化失败");
        resolve([]);
      }
    });
  }

  /** 添加失败的分片文件信息 */
  private addDownloadFileInfo(...fileInfo: SliceFileSqliteType[]): Promise<ResultSet[]> {
    return new Promise(async (resolve, reject) => {
      if (sliceFileSqlh) {
        const res = await sliceFileSqlh.inserts<SliceFileSqliteType[]>(fileInfo);
        resolve(res);
      } else {
        console.log("数据初始化失败");
        reject("数据初始化失败");
      }
    });
  }

  /** 删除失败的分片文件信息 */
  private delDownloadFileInfo(...keys: number[]): Promise<ResultSet> {
    return new Promise(async (resolve, reject) => {
      if (sliceFileSqlh) {
        const res = await sliceFileSqlh.deleteByArray(keys, sliceFileSqlh.getFieldKey(), "AND");
        resolve(res);
      } else {
        console.log("数据初始化失败");
        reject("数据初始化失败");
      }
    });
  }

  /** 分片下载文件 */
  sliceDownload(opt: SliceDownloadOptionType) {
    return new Promise<string | Error>(async (resolve, reject) => {
      try {
        this.info("分片文件下载: ", JSON.stringify(opt));
        // 本地所有待下载的文件信息
        const allUnfinishFileInfo = await this.readDownloadFileInfo();
        if (allUnfinishFileInfo.length) {
          opt.onSomeRestDownload && opt.onSomeRestDownload(allUnfinishFileInfo);
        }

        // 是否有当前需要下载的文件未下载成功
        const isCur = allUnfinishFileInfo.some(e => e.downloadFilePath === opt.downloadFilePath);

        // 是否下载剩余的部分
        const restDownload = typeof opt.restDownload === "undefined" ? true : opt.restDownload;

        if (isCur) {
          opt.onCurrentRestDownload && opt.onCurrentRestDownload(allUnfinishFileInfo);
          if (restDownload) {
            // 下载所有的文件信息
            const res = await this.restSliceFileDownload({
              allUnfinishFileInfo: allUnfinishFileInfo,
              onAfterSliceDownFile: opt.onAfterSliceDownFile,
              onBeforeSliceDownFile: opt.onBeforeSliceDownFile,
              onBuildSliceFile: opt.onBuildSliceFile
            });
            resolve(res);
            return;
          } else {
            // 只保留当前下载的文件信息
            const list = allUnfinishFileInfo.filter(e => e.downloadFilePath === opt.downloadFilePath);
            const res = await this.restSliceFileDownload({
              allUnfinishFileInfo: list,
              onAfterSliceDownFile: opt.onAfterSliceDownFile,
              onBeforeSliceDownFile: opt.onBeforeSliceDownFile,
              onBuildSliceFile: opt.onBuildSliceFile
            });
            resolve(res);
            return;
          }
        } else {
          if (allUnfinishFileInfo.length && restDownload) {
            // 下载未下载完成的切片文件
            await this.restSliceFileDownload({
              allUnfinishFileInfo: allUnfinishFileInfo,
              onAfterSliceDownFile: opt.onAfterSliceDownFile,
              onBeforeSliceDownFile: opt.onBeforeSliceDownFile,
              onBuildSliceFile: opt.onBuildSliceFile
            });
          }
        }

        let splitFiles: string[] = [];
        if (opt.downloadFilePath.indexOf("/") !== -1) {
          splitFiles = opt.downloadFilePath.split("/");
        } else if (opt.downloadFilePath.indexOf("\\") !== -1) {
          splitFiles = opt.downloadFilePath.split("\\");
        } else {
          resolve(new Error("路径异常, 请检查: " + opt.downloadFilePath));
        }

        // 文件名
        const fileName = splitFiles.pop();

        if (!fileName) {
          resolve(new Error("没有获取到文件名, 请检查: " + opt.downloadFilePath));
        }

        // 文件目录
        const fileDir = splitFiles.join("/");
        await this.mkdirDir(fileDir);

        // 总切片数
        const rangeCountSum = Math.ceil(opt.fileSize / opt.rangeSize);
        // 临时文件存储的目录
        const tempFileDir = `${this.sliceFileDir}/${fileName}`;
        await this.mkdirDir(tempFileDir);
        // 存储已经保存的文件路径
        const files: string[] = [];

        // 逐个请求
        for (let i = 0; i < rangeCountSum; i++) {
          const startRange = i * opt.rangeSize;
          const endRange = startRange + opt.rangeSize - 1;
          const filePath = `${tempFileDir}/${i + 1}`;

          // 先检查本地是否存在该分片文件, 存在则说明该文件已经下载成功
          const isExists = await RNFS.exists(filePath);
          if (isExists) {
            this.info("分片文件已经存在, 跳过下载: ", filePath);
            // 保存文件路径
            files.push(filePath);
            continue;
          }

          const headers = {
            ...opt.headers,
            Range: `bytes=${startRange}-${endRange}`
          };

          try {
            // TODO 测试下载失败
            const testError = typeof opt.testError === "undefined" ? false : opt.testError;
            if (testError) {
              if (i % 2 === 0) {
                throw new Error("测试文件下载错误");
              }
            }

            // 回调参数
            const cbp: DownFileCallbackParams = {
              startRange,
              endRange,
              rangeCountSum,
              currentCount: i + 1,
              downloadFilePath: opt.downloadFilePath,
              isRestSliceDownload: false
            };

            opt.onBeforeSliceDownFile && opt.onBeforeSliceDownFile(cbp);

            // 注意: 分片下载文件不能使用 addAndroidDownloads
            const res = await RNFetchBlob.config({
              path: filePath,
              fileCache: true
            })
              .fetch(opt.method, opt.url, headers)
              // 下载进度
              .progress({ interval: FileOperate.progressInterval }, (received, total) => {
                if (Number(received) === 0 && Number(total) === -1) {
                  this.info(`无法计算下载进度: received: ${received}, total: ${total} -> ${opt.url}`);
                } else {
                  const progress = (Number(received) / Number(total)) * 100;
                  this.info(`下载进度: ${progress.toFixed(2)}% -> ${opt.url}`);
                }
              });

            opt.onAfterSliceDownFile && opt.onAfterSliceDownFile({ ...cbp, response: res });

            // 保存文件路径
            files.push(filePath);
          } catch (err) {
            // 如果下载途中发生了错误, 记录当前下载的文件信息
            const saveFileInfo: SliceFileSqliteType = {
              // id: filePath,
              id: Date.now(),
              url: opt.url,
              method: opt.method,
              headers: JSON.stringify(headers),
              originFileSize: opt.fileSize,
              targetDir: tempFileDir,
              rangeSize: opt.rangeSize,
              targetFilePath: filePath,
              startRange,
              endRange,
              rangeCountSum,
              currentCount: i + 1,
              error: (err as any).toString(),
              downloadFilePath: opt.downloadFilePath,
              downTime: dayjs().format("YYYY-MM-DD HH:mm:ss")
            };
            await this.addDownloadFileInfo(saveFileInfo);
            opt.onSliceFileDownError && opt.onSliceFileDownError(saveFileInfo);
          }
        }

        const exists = await RNFS.exists(opt.downloadFilePath);
        if (exists) {
          this.info("本地已经存在文件, 不重复构建: ", opt.downloadFilePath);
          resolve(opt.downloadFilePath);
          return;
        }
        // 构建文件
        const buildOpt: BuildSliceToFileOption = {
          filePath: opt.downloadFilePath,
          tempFileDir,
          filePaths: files
        };

        // 这里不能并发执行
        const buildRes = await this.buildSliceToFile(buildOpt, opt.onBuildSliceFile);

        if (buildRes) {
          this.info("数据构建成功: ", buildRes);
          resolve(buildRes);
        } else {
          opt.onUnfinishFileDown &&
            opt.onUnfinishFileDown({
              ...buildOpt,
              errFileList: await this.readDownloadFileInfo()
            });
          resolve(buildRes);
        }
      } catch (err) {
        console.log("err: ", err);
        if (err instanceof Error) {
          resolve(err);
        } else {
          resolve(new Error("发生了错误"));
        }
      }
    });
  }

  /**
   * 下载剩余分片的文件
   */
  private restSliceFileDownload(
    opt: Pick<
      SliceDownloadOptionType,
      "onBeforeSliceDownFile" | "onAfterSliceDownFile" | "onUnfinishFileDown" | "onBuildSliceFile"
    > & {
      /** 所有的未下载完成的文件信息 */
      allUnfinishFileInfo: SliceFileSqliteType[];
    }
  ) {
    return new Promise<string | Error>(async (resolve, reject) => {
      try {
        // 所有待下载的文件信息(去重)
        const unfinishFileInfo: SliceFileSqliteType[] = [];
        opt.allUnfinishFileInfo.forEach(e => {
          if (!unfinishFileInfo.some(item => item.downloadFilePath === e.downloadFilePath)) {
            unfinishFileInfo.push(e);
          }
        });

        for (let i = 0; i < unfinishFileInfo.length; i++) {
          const target = unfinishFileInfo[i];
          const targetFileInfo = opt.allUnfinishFileInfo.filter(e => e.targetDir === target.targetDir);
          console.log("开始下载未下载完成的数据: ", targetFileInfo);

          for (let j = 0; j < targetFileInfo.length; j++) {
            const item = targetFileInfo[j];

            // 回调参数
            const cbp: DownFileCallbackParams = {
              ...target,
              currentCount: j + 1,
              isRestSliceDownload: true
            };

            opt.onBeforeSliceDownFile && opt.onBeforeSliceDownFile(cbp);

            const res = await RNFetchBlob.config({
              path: item.targetFilePath,
              fileCache: true
            })
              .fetch(item.method, item.url, typeof item.headers === "string" ? JSON.parse(item.headers) : item.headers)
              // 下载进度
              .progress({ interval: FileOperate.progressInterval }, (received, total) => {
                if (Number(received) === 0 && Number(total) === -1) {
                  this.info(`无法计算下载进度: received: ${received}, total: ${total} -> ${item.url}`);
                } else {
                  const progress = (Number(received) / Number(total)) * 100;
                  this.info(`下载进度: ${progress.toFixed(2)}% -> ${item.url}`);
                }
              });

            opt.onAfterSliceDownFile && opt.onAfterSliceDownFile({ ...cbp, response: res });

            console.log("删除已经下载完成的切片文件信息: ", item.id);
            await this.delDownloadFileInfo(item.id);
          }
          const files = await this.readDir(target.targetDir);
          // 排序
          const sortFiles = files.sort((a, b) => Number(a) - Number(b)).map(e => `${target.targetDir}/${e}`);
          // 构建文件
          const buildOpt: BuildSliceToFileOption = {
            filePath: target.downloadFilePath,
            tempFileDir: target.targetDir,
            filePaths: sortFiles
          };

          const buildRes = await this.buildSliceToFile(buildOpt, opt.onBuildSliceFile);

          if (buildRes) {
            opt.onUnfinishFileDown &&
              opt.onUnfinishFileDown({
                ...buildOpt,
                errFileList: await this.readDownloadFileInfo()
              });
            resolve(buildRes);
          } else {
            console.log("buildRes: ", buildRes);
            resolve(new Error("数据构建失败"));
          }
        }
      } catch (err) {
        if (err instanceof Error) {
          resolve(err);
        } else {
          resolve(new Error("发生了异常"));
        }
      }
    });
  }

  /** 分片文件构建完整文件 */
  private async buildSliceToFile(opt: BuildSliceToFileOption, cb: SliceDownloadOptionType["onBuildSliceFile"]) {
    return new Promise<string | Error>(async (resolve, reject) => {
      try {
        const infoList = await this.readDownloadFileInfo();
        // 判断是否存在下载失败的数据
        const isSuccess = infoList.some(e => e.targetDir === opt.tempFileDir);
        if (isSuccess) {
          const tip = `${opt.tempFileDir} 未下载完成, 不合并文件`;
          resolve(new Error(tip));
        } else {
          cb && cb(opt);
          await this.rm(opt.filePath);

          // 读取临时文件合并成最终文件
          for (let i = 0; i < opt.filePaths.length; i++) {
            const item = opt.filePaths[i];
            this.info(`读取`, item, `追加数据到`, opt.filePath);
            const content = await RNFS.readFile(item, "ascii");
            await RNFS.appendFile(opt.filePath, content, "ascii");
            if (config.IS_DEBUG) {
              console.log("数据追加完成, 当前是测试环境, 不删除切片文件: ", item);
            } else {
              this.info("数据追加完成, 删除切片文件: ", item);
              await this.rm(item);
            }
          }
          if (config.IS_DEBUG) {
            console.log("切片文件合并完成, 当前是测试环境, 不删除切片文件目录: ", opt.tempFileDir);
          } else {
            this.info("切片文件合并完成, 删除切片文件目录: ", opt.tempFileDir);
            await this.rm(opt.tempFileDir);
          }
          resolve(opt.filePath);
        }
      } catch (err) {
        // 这里要删除合并失败的最终文件
        await this.rm(opt.filePath);
        reject(err);
      }
    });
  }

  /** 截图保存到 screenshotDir 目录 */
  public captureScreen() {
    return new Promise<
      | {
          /** 文件地址 */
          filePath: string;
          /** 文件名 */
          fileName: string;
        }
      | Error
    >(async resolve => {
      try {
        // 保险一点, 这里要判断一下目录是否存在
        await this.init();

        const isFlag = await Module.isRoot();
        const isPerm = await PermissionsAndroid.check("android.permission.WRITE_EXTERNAL_STORAGE");
        // 有 root 权限并且有外部文件读写权限
        if (isFlag && isPerm) {
          const fileName = Date.now().toString() + ".png";
          const filePath = `${this.screenshotDir}/${fileName}`;
          const cmdText = `/system/bin/screencap -p ${filePath}`;
          const res = await Module.execShell(cmdText, true);
          if (res) {
            if (res.exitValue === 0) {
              resolve({ filePath, fileName });
            } else {
              resolve(new Error(res.stderr));
            }
          } else {
            resolve(new Error("执行命令失败: " + cmdText));
          }
        } else {
          const opt: CaptureOptions = {
            fileName: Date.now().toString(),
            format: "jpg",
            quality: 0.8
          };
          const url = await captureScreen(opt);
          const fileName = `${opt.fileName}.${opt.format}`;
          // 移动到指定的目录
          const filePath = `${this.screenshotDir}/${fileName}`;
          await RNFS.moveFile(url, filePath);
          resolve({ filePath, fileName });
        }
      } catch (err) {
        resolve(new Error(`${err}`));
      }
    });
  }

  /** 格式化路径为人类可读的 */
  public formatPath(path: string) {
    return path.replace(FileOperate.downDir, "文件/下载");
  }

  //// 普通记录日志方法
  public info(...args: any[]) {
    return this.appendLogFile("INFO", ...args);
  }

  public warn(...args: any[]) {
    return this.appendLogFile("WARN", ...args);
  }

  public error(...args: any[]) {
    return this.appendLogFile("ERROR", ...args);
  }
  ////
}
